home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / utils / from.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-31  |  22.0 KB  |  816 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: from.c,v 5.14 1993/05/31 19:36:07 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.14 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1988-1992 USENET Community Trust
  8.  *             Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: from.c,v $
  17.  * Revision 5.14  1993/05/31  19:36:07  syd
  18.  * Dave Thomas forgot to update the NLS message file when he added the tidy
  19.  * option to frm.  While I was at it, I did a little cleanup to keep things
  20.  * alphabetized.
  21.  * From: dwolfe@pffft.sps.mot.com (Dave Wolfe)
  22.  *
  23.  * Revision 5.13  1993/05/14  03:58:37  syd
  24.  * This is a trivial patch to 'from.c' to tidy up the output is
  25.  * the cases where the 'from' part is longer that 20 characters.
  26.  * It adds the new '-t' (for tidy) option:
  27.  * From: dave@devteq.co.uk (Dave Thomas)
  28.  *
  29.  * Revision 5.12  1993/05/14  03:57:10  syd
  30.  * When frm checked for file access on a POSIX system there
  31.  * was a test `&& S_ISREG(mode)' instead of `&& ! S_ISREG(mode)'
  32.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  33.  *
  34.  * Revision 5.11  1993/04/21  01:18:09  syd
  35.  * frm treated a line with From_ preceeded by whitespace as a valid
  36.  * message delimiter.
  37.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  38.  *
  39.  * Revision 5.10  1993/04/12  03:33:39  syd
  40.  * the posix macros to interpret the result of the stat-call.
  41.  * From: vogt@isa.de (Gerald Vogt)
  42.  *
  43.  * Revision 5.9  1993/04/12  02:25:16  syd
  44.  * remove extra blank in the new  messages line
  45.  *
  46.  * Revision 5.8  1993/01/27  21:07:55  syd
  47.  * if no files are given to frm, and it cannot open the mail spool,
  48.  * print No mail.
  49.  *
  50.  * Revision 5.7  1993/01/27  20:52:20  syd
  51.  * fixed the behaviour of the tool nfrm or frm -snew to be inconsistent
  52.  * with elm itself. In from.c it never recognized the file in the MAIL
  53.  * environment variable to be a SPOOL file as you say in the source.
  54.  * From: Erick Otto <eotto@hvlpa.ns-nl.att.com>
  55.  *
  56.  * Revision 5.6  1993/01/19  05:07:05  syd
  57.  * Trim erroreous extra log entry
  58.  * From: Syd
  59.  *
  60.  * Revision 5.5  1993/01/19  04:47:12  syd
  61.  * Significant changes to provide consistent Date and From_ header
  62.  * cracking.  Overhauled date utilities and moved into library.  Moved
  63.  * real_from() into library.  Modified frm, newmail, and readmsg utilities
  64.  * to use library version of real_from().  Moved get_word() from Elm
  65.  * source into library.  Added new library routines atonum() and strfcpy().
  66.  * Fixed trailing backslash bug in len_next().
  67.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  68.  *
  69.  * Revision 5.4  1992/12/11  01:45:04  syd
  70.  * remove sys/types.h include, it is now included by defs.h
  71.  * and this routine includes defs.h or indirectly includes defs.h
  72.  * From: Syd
  73.  *
  74.  * Revision 5.3  1992/11/07  21:03:33  syd
  75.  * fix typo
  76.  *
  77.  * Revision 5.2  1992/11/07  20:05:52  syd
  78.  * change to use header_cmp to allow for linear white space around the colon
  79.  * From: Syd
  80.  *
  81.  * Revision 5.1  1992/10/04  00:46:45  syd
  82.  * Initial checkin as of 2.4 Release at PL0
  83.  *
  84.  *
  85.  ******************************************************************************/
  86.  
  87. /** print out whom each message is from in the pending folder or specified 
  88.     one, including a subject line if available.
  89.  
  90. **/
  91.  
  92. #include "elmutil.h"
  93. #include "s_from.h"
  94.      
  95. #ifdef PWDINSYS
  96. #  include <sys/pwd.h>
  97. #else
  98. #  include <pwd.h>
  99. #endif
  100. #include <sys/stat.h>
  101.  
  102. #define LINEFEED    (char) 10
  103.  
  104. #define metachar(c)    (c == '=' || c == '+' || c == '%')
  105.  
  106. /* ancient wisdom */
  107. #ifndef TRUE
  108. #  define TRUE    1
  109. #  define FALSE    0
  110. #endif
  111.  
  112. /* for explain(), positive and negative */
  113. #define POS    1
  114. #define NEG    0
  115.  
  116. /* defines for selecting messages by Status: */
  117. #define NEW_MSG        0x1
  118. #define OLD_MSG        0x2
  119. #define READ_MSG    0x4
  120. #define UNKNOWN        0x8
  121.  
  122. #define ALL_MSGS    0xf
  123.  
  124. /* exit statuses */
  125. #define    EXIT_SELECTED    0    /* Selected messages present */
  126. #define    EXIT_MAIL    1    /* Mail present, but no selected messages */
  127. #define    EXIT_NO_MAIL    2    /* No messages at all */
  128. #define    EXIT_ERROR    3    /* Error */
  129.  
  130. FILE *mailfile;
  131.  
  132. int   number = FALSE,    /* should we number the messages?? */
  133.       veryquiet = FALSE,/* should we be print any output at all? */
  134.       quiet = FALSE,    /* only print mail/no mail and/or summary */
  135.       selct = FALSE,    /* select these types of messages */
  136.       tidy  = FALSE,    /* tidy output with long 'from's */
  137.       summarize = FALSE,/* print a summary of how many messages of each type */
  138.       verbose = FALSE;    /* and should we prepend a header? */
  139.  
  140. char infile[SLEN];    /* current file name */
  141. char defaultfile[SLEN];    /* default file name */
  142. char realname[SLEN];    /* the username of the user who ran the program */
  143.  
  144. extern char *whos_mail(), *explain();
  145.  
  146. #ifdef DEBUG
  147. int debug = 0;
  148. FILE *debugfile = stderr;
  149. #endif
  150.  
  151.  
  152. main(argc, argv)
  153. int argc;
  154. char *argv[];
  155. {
  156.     char *cp;
  157.     int  multiple_files = FALSE, output_files = FALSE;
  158.     int  user_mailbox = FALSE, no_files, c;
  159.     struct passwd *pass;
  160. #ifndef    _POSIX_SOURCE
  161.     struct passwd *getpwuid();
  162. #endif
  163.     int hostlen, domlen;
  164.     int total_msgs = 0, selected_msgs = 0;
  165.     int file_exists;
  166.     struct stat statbuf;
  167.  
  168.     extern int optind;
  169.     extern char *optarg;
  170.  
  171. #ifdef I_LOCALE
  172.     setlocale(LC_ALL, "");
  173. #endif
  174.  
  175.     elm_msg_cat = catopen("elm2.4", 0);
  176.  
  177.     /*
  178.      * check the first character of the command basename to
  179.      * use as the selection criterion.
  180.      */
  181.     cp = argv[0] + strlen(argv[0]) - 1;
  182.     while (cp != argv[0] && cp[-1] != '/')
  183.       cp--;
  184.     switch (*cp) {
  185.       case 'n': selct |= NEW_MSG;  break;
  186.       case 'u':
  187.       case 'o': selct |= OLD_MSG;  break;
  188.       case 'r': selct |= READ_MSG; break;
  189.     }
  190.  
  191.     while ((c = getopt(argc, argv, "hnQqSs:tv")) != EOF) 
  192.       switch (c) {
  193.         case (int)'n': number++;    break;
  194.         case (int)'Q': veryquiet++;    break;
  195.         case (int)'q': quiet++;    break;
  196.         case (int)'S': summarize++; break; 
  197.         case (int)'t': tidy++;      break;
  198.         case (int)'v': verbose++;    break;
  199.         case (int)'s': if (optarg[1] == '\0') {
  200.                  switch (*optarg) {
  201.                    case 'n':
  202.                    case 'N': selct |= NEW_MSG;  break;
  203.                    case 'o':
  204.                    case 'O':
  205.                    case 'u':
  206.                    case 'U': selct |= OLD_MSG;  break;
  207.                    case 'r':
  208.                    case 'R': selct |= READ_MSG; break;
  209.                    default:       usage(argv[0]);
  210.                           exit(EXIT_ERROR);
  211.                  }
  212.                } else if (istrcmp(optarg,"new") == 0)
  213.                  selct |= NEW_MSG;
  214.                else if (istrcmp(optarg,"old") == 0)
  215.                  selct |= OLD_MSG;
  216.                else if (istrcmp(optarg,"unread") == 0)
  217.                  selct |= OLD_MSG;
  218.                else if (istrcmp(optarg,"read") == 0)
  219.                  selct |= READ_MSG;
  220.                else {
  221.                  usage(argv[0]);
  222.                  exit(EXIT_ERROR);
  223.                }
  224.                break;
  225.         case (int)'h': print_help();
  226.                exit(EXIT_ERROR);
  227.         case (int)'?': usage(argv[0]);
  228.                printf(catgets(elm_msg_cat,
  229.                       FromSet,FromForMoreInfo,
  230.                 "For more information, type \"%s -h\"\n"),
  231.                    argv[0]);
  232.                        exit(EXIT_ERROR);
  233.       }
  234.  
  235.     if (quiet && verbose) {
  236.       fprintf(stderr,catgets(elm_msg_cat,FromSet,FromNoQuietVerbose,
  237.                  "Can't have quiet *and* verbose!\n"));
  238.       exit(EXIT_ERROR);
  239.     }
  240.  
  241.     if (veryquiet) {
  242.       if (freopen("/dev/null", "w", stdout) == NULL) {
  243.         fprintf(stderr,catgets(elm_msg_cat,FromSet,FromCantOpenDevNull,
  244.             "Can't open /dev/null for \"very quiet\" mode.\n"));
  245.         exit(EXIT_ERROR);
  246.       }
  247.     }
  248.  
  249.     /* default is all messages */
  250.     if (selct == 0 || selct == (NEW_MSG|OLD_MSG|READ_MSG))
  251.       selct = ALL_MSGS;
  252.  
  253.     if((pass = getpwuid(getuid())) == NULL) {
  254.       fprintf(stderr,catgets(elm_msg_cat,FromSet,FromNoPasswdEntry,
  255.                  "You have no password entry!"));
  256.       exit(EXIT_ERROR);
  257.     }
  258.  
  259.     strcpy(username,pass->pw_name);
  260.     strcpy(realname,username);
  261.  
  262.     /*
  263.      * from init.c: Get the host name as per configured behavior.
  264.      */
  265. #ifdef HOSTCOMPILED
  266.     strncpy(hostname, HOSTNAME, sizeof(hostname) - 1);
  267.     hostname[sizeof(hostname) - 1] = '\0';
  268. #else
  269.     gethostname(hostname, sizeof(hostname));
  270. #endif
  271.     gethostdomain(hostdomain, sizeof(hostdomain));
  272.  
  273.     /*
  274.      * see init.c for an explanation of this!
  275.      */
  276.     hostlen = strlen(hostname);
  277.     domlen = strlen(hostdomain);
  278.     if (hostlen >= domlen) {
  279.       if (istrcmp(&hostname[hostlen - domlen], hostdomain) == 0)
  280.         strcpy(hostfullname, hostname);
  281.       else {
  282.         strcpy(hostfullname, hostname);
  283.         strcat(hostfullname, hostdomain);
  284.       }
  285.     } else {
  286.       if (istrcmp(hostname, hostdomain + 1) == 0)
  287.         strcpy(hostfullname, hostname);
  288.       else {
  289.         strcpy(hostfullname, hostname);
  290.         strcat(hostfullname, hostdomain);
  291.       }
  292.     }
  293.  
  294.     infile[0] = '\0';
  295.     defaultfile[0] = '\0';
  296.  
  297.     if (no_files = optind == argc) { /* assignment intentional */
  298.     /*
  299.      *    determine mail file from environment variable if found,
  300.      *    else use password entry
  301.      */
  302.       if ((cp = getenv("MAIL")) == NULL) {
  303.         sprintf(infile,"%s%s",mailhome, username);
  304.       }
  305.       else {
  306.         strcpy(defaultfile, cp);
  307.         strcpy(infile, cp);
  308.       }
  309.       optind -= 1;    /* ensure one pass through loop */
  310.     }
  311.  
  312.     multiple_files = (argc - optind > 1);
  313.  
  314.     for ( ; optind < argc; optind++) {
  315.     
  316.       /* copy next argument into infile */
  317.  
  318.       if (multiple_files) {
  319.         strcpy(infile, argv[optind]);
  320.         printf("%s%s: \n", output_files++ > 0 ? "\n":"", infile);
  321.       }
  322.       else if (infile[0] == '\0')
  323.         strcpy(infile, argv[optind]);
  324.  
  325.       if (metachar(infile[0])) {
  326.         if (expand(infile) == 0) {
  327.            fprintf(stderr,catgets(elm_msg_cat,
  328.                       FromSet,FromCouldntExpandFilename,
  329.                       "%s: couldn't expand filename %s!\n"), 
  330.                argv[0], infile);
  331.            exit(EXIT_ERROR);
  332.         }
  333.       }
  334.  
  335.  
  336.       /* check if this is a mailbox or not, and attempt to open it */
  337.  
  338.       if (strncmp(infile, mailhome, strlen(mailhome)) == 0)
  339.         user_mailbox = TRUE;
  340.       else
  341.         user_mailbox = FALSE;
  342.  
  343.       /* if file name == default mailbox, its a spool file also
  344.        * even if its not in the spool directory. (SVR4)
  345.        */
  346.        if (strcmp(infile, defaultfile) == 0)
  347.          user_mailbox = TRUE;
  348.  
  349.       /* pardon the oversimplification here */
  350.       if (stat(infile, &statbuf) == -1)
  351.         file_exists = FALSE;
  352.       else
  353.         file_exists = TRUE;
  354.  
  355.       if (file_exists
  356. #ifndef    _POSIX_SOURCE
  357.           && (statbuf.st_mode & S_IFMT) != S_IFREG
  358. #else
  359.           && ! S_ISREG(statbuf.st_mode)
  360. #endif
  361.           ) {
  362.         printf(catgets(elm_msg_cat,FromSet,FromNotRegularFile,
  363.                "\"%s\" is not a regular file!\n"), infile);
  364.         continue;
  365.       }
  366.  
  367.       if ((mailfile = fopen(infile,"r")) == NULL) {
  368.         if ((user_mailbox && file_exists && statbuf.st_size == 0) || no_files) {
  369.         if (!veryquiet)
  370.           printf(catgets(elm_msg_cat,FromSet,FromNoMail,"No mail.\n"));
  371.         }
  372.         else {
  373.           if (infile[0] == '/' || file_exists == TRUE) 
  374.             printf(catgets(elm_msg_cat,FromSet,FromCouldntOpenFolder,
  375.                    "Couldn't open folder \"%s\".\n"), infile);
  376.           else {
  377.         /* only try mailhome if file not found */
  378.         sprintf(infile,"%s%s", mailhome, argv[optind]);
  379.         if ((mailfile = fopen(infile,"r")) == NULL) {
  380.           printf(catgets(elm_msg_cat,
  381.                  FromSet,FromCouldntOpenFolderPlural,
  382.                  "Couldn't open folders \"%s\" or \"%s\".\n"),
  383.              argv[optind], infile);
  384.           continue;    /* let's try the next file */
  385.         } else
  386.           user_mailbox = TRUE;
  387.           }
  388.         }
  389.       }
  390.  
  391.       /* if the open was successful, read the headers */
  392.  
  393.       if (mailfile != NULL) {
  394.         /*
  395.          * if this is a mailbox, use the identity of the mailbox owner.
  396.          * this affects the "To" processing.
  397.          */
  398.         if (strncmp(infile, mailhome, strlen(mailhome)) == 0)
  399.           strcpy(username, infile+strlen(mailhome));
  400.         else
  401.           strcpy(username, realname);
  402.  
  403.         /*
  404.          * then get full username
  405.          */
  406.         if((cp = get_full_name(username)) != NULL)
  407.           strcpy(full_username, cp);
  408.         else
  409.           strcpy(full_username, username);
  410.  
  411.         read_headers(user_mailbox, &total_msgs, &selected_msgs);
  412.  
  413.         /*
  414.          * we know what to say; now we have to figure out *how*
  415.          * to say it!
  416.          */
  417.  
  418.         /* no messages at all? */
  419.         if (total_msgs == 0) {
  420.           if (user_mailbox)
  421.         printf(catgets(elm_msg_cat,FromSet,FromStringNoMail,
  422.                    "%s no mail.\n"), whos_mail(infile));
  423.           else
  424.         if (!summarize)
  425.           printf(catgets(elm_msg_cat,FromSet,FromNoMesgInFolder,
  426.                  "No messages in that folder!\n"));
  427.         }
  428.         else
  429.           /* no selected messages then? */
  430.           if (selected_msgs == 0) {
  431.         if (user_mailbox)
  432.           printf(catgets(elm_msg_cat,FromSet,FromNoExplainMail,
  433.                  "%s no %s mail.\n"), whos_mail(infile),
  434.              explain(selct,NEG));
  435.         else
  436.           if (!summarize)
  437.             printf(catgets(elm_msg_cat,
  438.                    FromSet,FromNoExplainMessages,
  439.                    "No %s messages in that folder.\n"),
  440.                explain(selct,NEG));
  441.           }
  442.           else
  443.         /* there's mail, but we just want a one-liner */
  444.         if (quiet && !summarize) {
  445.           if (user_mailbox)
  446.             printf(catgets(elm_msg_cat,FromSet,FromStringStringMail,
  447.                    "%s %s mail.\n"), whos_mail(infile),
  448.                explain(selct,POS));
  449.           else
  450.             printf(catgets(elm_msg_cat,FromSet,FromThereAreMesg,
  451.                    "There are %s messages in that folder.\n"),
  452.                 explain(selct,POS));
  453.         }
  454.         fclose(mailfile);
  455.       }
  456.  
  457.     } /* for each arg */
  458.  
  459.     /*
  460.      * return "shell true" (0) if there are selected messages;
  461.      * 1 if there are messages, but no selected messages;
  462.      * 2 if there are no messages at all.
  463.      */
  464.     if (selected_msgs > 0)
  465.       exit(EXIT_SELECTED);
  466.     else if (total_msgs > 0)
  467.       exit(EXIT_MAIL);
  468.     else
  469.       exit(EXIT_NO_MAIL);
  470. }
  471.  
  472. read_headers(user_mailbox, total_msgs, selected)
  473. int user_mailbox;
  474. int *total_msgs;
  475. int *selected;
  476. {
  477.     /** Read the headers, output as found.  User-Mailbox is to guarantee
  478.         that we get a reasonably sensible message from the '-v' option
  479.      **/
  480.  
  481.     struct header_rec hdr;
  482.     char buffer[SLEN], to_whom[SLEN], from_whom[SLEN], subject[SLEN];
  483.     char who[SLEN];
  484.     register int in_header = FALSE, count = 0, selected_msgs = 0;
  485.     int status, i;
  486.     int lenWho;
  487.     int summary[ALL_MSGS];
  488. #ifdef MMDF
  489.     int newheader = FALSE;
  490. #endif /* MMDF */
  491.  
  492.     for (i=0; i<ALL_MSGS; i++)
  493.       summary[i] = 0;
  494.  
  495.     while (mail_gets(buffer, SLEN, mailfile) != 0) {
  496.       if (index(buffer, '\n') == NULL && !feof(mailfile)) {
  497.         int c;
  498.         while ((c = getc(mailfile)) != EOF && c != '\n')
  499.           ; /* keep reading */
  500.       }
  501.  
  502. #ifdef MMDF
  503.           if (strcmp(buffer, MSG_SEPARATOR) == 0) {
  504.         newheader = !newheader;
  505.         if (newheader) {
  506.           subject[0] = '\0';
  507.           to_whom[0] = '\0';
  508.           in_header = TRUE;
  509.           if (user_mailbox)
  510.         status = NEW_MSG;
  511.           else
  512.         status = READ_MSG;
  513.         }
  514.       }
  515. #else
  516.       if (first_word(buffer, "From ") && real_from(buffer, &hdr)) {
  517.         strcpy(from_whom, hdr.from);
  518.         subject[0] = '\0';
  519.         to_whom[0] = '\0';
  520.         in_header = TRUE;
  521.         if (user_mailbox)
  522.           status = NEW_MSG;
  523.         else
  524.           status = READ_MSG;
  525.       }
  526. #endif /* MMDF */
  527.       else if (in_header) {
  528. #ifdef MMDF
  529.         if (real_from(buffer, &hdr))
  530.           strcpy(from_whom, hdr.from);
  531.         else
  532. #endif /* MMDF */
  533.         if (first_word(buffer,">From ")) 
  534.           forwarded(buffer, from_whom); /* return address */
  535.         else if (header_cmp(buffer,"Subject", NULL) ||
  536.              header_cmp(buffer,"Re", NULL)) {
  537.           if (subject[0] == '\0') {
  538.             remove_header_keyword(buffer);
  539.         strcpy(subject, buffer);
  540.           }
  541.         }
  542.         else if (header_cmp(buffer,"From", NULL) ||
  543.              header_cmp(buffer, ">From", NULL))
  544.           parse_arpa_who(buffer, from_whom, FALSE);
  545.         else if (header_cmp(buffer, "To", NULL))
  546.           figure_out_addressee(index(buffer, ':') + 1, to_whom);
  547.         else if (header_cmp(buffer, "Status", NULL)) {
  548.           remove_header_keyword(buffer);
  549.           switch (*buffer) {
  550.         case 'N': status = NEW_MSG;    break;
  551.         case 'O': status = OLD_MSG;    break;
  552.         case 'R': status = READ_MSG;    break;
  553.         default:  status = UNKNOWN;    break;
  554.           }
  555.           if (buffer[0] == 'O' && buffer[1] == 'R')
  556.         status = READ_MSG;
  557.         }
  558.         else if (buffer[0] == LINEFEED) {
  559.           in_header = FALSE;
  560. #ifdef MMDF
  561.           if (*from_whom == '\0')
  562.                 strcpy(from_whom,username);
  563. #endif /* MMDF */
  564.           count++;
  565.           summary[status]++;
  566.  
  567.           if ((status & selct) != 0) {
  568.  
  569.         /* what a mess! */
  570.         if (verbose && selected_msgs == 0) {
  571.           if (user_mailbox) {
  572.             if (selct == ALL_MSGS)
  573.               printf(catgets(elm_msg_cat,FromSet,FromFollowingMesg,
  574.                      "%s the following mail messages:\n"),
  575.                   whos_mail(infile));
  576.             else
  577.               printf(catgets(elm_msg_cat,FromSet,FromStringStringMail,
  578.                      "%s %s mail.\n"), whos_mail(infile),
  579.                  explain(selct,POS));
  580.           }
  581.           else
  582.             printf(catgets(elm_msg_cat,
  583.                    FromSet,FromFolderContainsFollowing,
  584.             "Folder contains the following %s messages:\n"),
  585.                 explain(selct,POS));
  586.         }
  587.  
  588.         selected_msgs++;
  589.         if (! quiet) {
  590.           if (tail_of(from_whom, who, to_whom) == 1) {
  591.             strcpy(buffer, "To ");
  592.             strcat(buffer, who);
  593.             strcpy(who, buffer);
  594.           }
  595.  
  596.           /***
  597.           *    Print subject on next line if the Who part blows
  598.           *    the alignment
  599.           ***/
  600.           
  601.           if (tidy) 
  602.             lenWho = strlen(who);
  603.           else
  604.             lenWho = 0;            /* forces op on same line */
  605.           
  606.           if (number)
  607.             printf("%3d: %-20s%c%*s%s\n", count, who, 
  608.                 lenWho > 20 ? '\n' : ' ',
  609.                 lenWho > 20 ? 27   :   1, "",
  610.                     subject);
  611.           else
  612.             printf("%-20s%c%*s%s\n", who, 
  613.                 lenWho > 20 ? '\n' : ' ',
  614.                 lenWho > 20 ? 22   :   1, "",
  615.                 subject);
  616.         }
  617.           }
  618.         }
  619.       }
  620.     }
  621.  
  622.     *selected = selected_msgs;
  623.     *total_msgs = count;
  624.  
  625.     /* print a message type summary */
  626.  
  627.     if (summarize) {
  628.       int output=FALSE, unknown = 0;
  629.  
  630.       if (user_mailbox)
  631.         printf("%s ", whos_mail(infile));
  632.       else
  633.         printf(catgets(elm_msg_cat,FromSet,FromFolderContains,
  634.                "Folder contains "));
  635.  
  636.       for (i=0; i<ALL_MSGS; i++) {
  637.         if (summary[i] > 0) {
  638.           if (output)
  639.         printf(", ");
  640.           switch (i) {
  641.         case NEW_MSG:
  642.         case OLD_MSG:
  643.         case READ_MSG:
  644.           printf("%d %s ",summary[i], explain(i,POS));
  645.           if (summary[i] == 1)
  646.                printf("%s",catgets(elm_msg_cat,
  647.                    FromSet,FromMessage,"message"));
  648.           else
  649.                printf("%s",catgets(elm_msg_cat,
  650.                    FromSet,FromMessagePlural,"messages"));
  651.           
  652.           output = TRUE;
  653.           break;
  654.         default:
  655.           unknown += summary[i];
  656.           }
  657.         }
  658.       }
  659.       if (unknown)
  660.       {
  661.            printf("%d ",unknown);
  662.            
  663.            if (unknown == 1)
  664.             printf("%s",catgets(elm_msg_cat,
  665.                     FromSet,FromMessage,"message"));
  666.            else
  667.             printf("%s",catgets(elm_msg_cat,
  668.                     FromSet,FromMessagePlural,"messages"));
  669.            
  670.            printf("%s "," of unknown status");
  671.            output = TRUE;
  672.       }
  673.       
  674.       if (output)
  675.         printf(".\n");
  676.       else
  677.         printf(catgets(elm_msg_cat,FromSet,FromNoMessages,
  678.                        "no messages.\n"));
  679.     }
  680. }
  681.  
  682.  
  683. forwarded(buffer, who)
  684. char *buffer, *who;
  685. {
  686.     /** change 'from' and date fields to reflect the ORIGINATOR of 
  687.         the message by iteratively parsing the >From fields... **/
  688.  
  689.     char machine[SLEN], buff[SLEN], holding_from[SLEN];
  690.  
  691.     machine[0] = '\0';
  692.     holding_from[0] = '\0';
  693.     sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %s",
  694.                 holding_from, machine);
  695.  
  696.     if(machine[0] == '\0')    /* try for address with timezone in date */
  697.     sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
  698.                 holding_from, machine);
  699.  
  700.     if (machine[0] == '\0') /* try for srm address */
  701.       sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
  702.                 holding_from, machine);
  703.  
  704.     if (machine[0] == '\0')
  705.       sprintf(buff, holding_from[0] ? holding_from :
  706.           catgets(elm_msg_cat,FromSet,FromAnon, "anonymous"));
  707.     else
  708.       sprintf(buff,"%s!%s", machine, holding_from);
  709.  
  710.     strncpy(who, buff, SLEN);
  711. }
  712.  
  713. /*
  714.  * Return an appropriate string as to whom this mailbox belongs.
  715.  */
  716. char *
  717. whos_mail(filename)
  718. char *filename;
  719. {
  720.     static char whos_who[SLEN];
  721.     char *mailname;
  722.  
  723.     if (strncmp(filename, mailhome, strlen(mailhome)) == 0) {
  724.       mailname = filename + strlen(mailhome);
  725.       if (*mailname == '/')
  726.         mailname++;
  727.       if (strcmp(mailname, realname) == 0)
  728.         strcpy(whos_who,catgets(elm_msg_cat,
  729.                     FromSet,FromYouHave,"You have"));
  730.       else {
  731.         strcpy(whos_who, mailname);
  732.         strcat(whos_who,catgets(elm_msg_cat,FromSet,FromHas, " has"));
  733.       }
  734.     }
  735.     else
  736.     /* punt... */
  737.          strcpy(whos_who,catgets(elm_msg_cat,
  738.                      FromSet,FromYouHave,"You have"));
  739.  
  740.     return whos_who;
  741. }
  742.  
  743. usage(prog)
  744. char *prog;
  745. {
  746.      printf(catgets(elm_msg_cat,FromSet,FromUsage,
  747.     "Usage: %s [-n] [-v] [-t] [-s {new|old|read}] [filename | username] ...\n"),
  748.         prog);
  749. }
  750.  
  751. print_help()
  752. {
  753.  
  754.      printf(catgets(elm_msg_cat,FromSet,FromHelpTitle,
  755.  "frm -- list from and subject lines of messages in mailbox or folder\n"));
  756.             
  757.      usage("frm");
  758.      printf(catgets(elm_msg_cat,FromSet,FromHelpText,
  759. "\noption summary:\n\
  760. -h\tprint this help message.\n\
  761. -n\tdisplay the message number of each message printed.\n\
  762. -Q\tvery quiet -- no output is produced.  This option allows shell\n\
  763. \tscripts to check frm's return status without having output.\n\
  764. -q\tquiet -- only print summaries for each mailbox or folder.\n\
  765. -S\tsummarize the number of messages in each mailbox or folder.\n\
  766. -s status only -- select messages with the specified status.\n\
  767. \t'status' is one of \"new\", \"old\", \"unread\" (same as \"old\"),\n\
  768. \tor \"read\".  Only the first letter need be specified.\n\
  769. -t\ttry to align subjects even if 'from' text is long.\n\
  770. -v\tprint a verbose header.\n"));
  771.  
  772. }
  773.  
  774. /* explanation of messages visible after selection */
  775. /* usage: "... has the following%s messages ...", explain(selct,POS) */
  776.  
  777. char *
  778. explain(selection, how_to_say)
  779. int selection;
  780. int how_to_say;
  781. {
  782.     switch (selection) {
  783.       case NEW_MSG:
  784.         return catgets(elm_msg_cat,FromSet,FromNew,"new");
  785.       case OLD_MSG:
  786.         return catgets(elm_msg_cat,FromSet,FromUnread,"unread");
  787.       case READ_MSG:
  788.         return catgets(elm_msg_cat,FromSet,FromRead,"read");
  789.       case (NEW_MSG|OLD_MSG):
  790.         if (how_to_say == POS)
  791.           return catgets(elm_msg_cat,FromSet,FromNewAndUnread,
  792.                  "new and unread");
  793.         else
  794.           return catgets(elm_msg_cat,FromSet,FromNewOrUnread,
  795.                  "new or unread");
  796.       case (NEW_MSG|READ_MSG):
  797.         if (how_to_say == POS)
  798.           return catgets(elm_msg_cat,FromSet,FromNewAndRead,
  799.                  "new and read");
  800.         else
  801.           return catgets(elm_msg_cat,FromSet,FromNewOrRead,
  802.                  "new or read");
  803.       case (READ_MSG|OLD_MSG):
  804.         if (how_to_say == POS)
  805.           return catgets(elm_msg_cat,FromSet,FromReadAndUnread,
  806.                  "read and unread");
  807.         else
  808.           return catgets(elm_msg_cat,FromSet,FromReadOrUnread,
  809.                  "read or unread");
  810.       case ALL_MSGS:
  811.         return "";
  812.       default:
  813.         return catgets(elm_msg_cat,FromSet,FromUnknown,"unknown");
  814.     }
  815. }
  816.